package gaml.testing;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import gaml.error.GamlException;
import gaml.java.ClassSerializerStore;
import gaml.java.NodeObjectBridge;
import gaml.java.serializer.ComplexSerializerFactory;
import gaml.java.serializer.ObjectSerializer;
import gaml.java.serializer.primitive.IntegerSerializer;
import gaml.java.serializer.primitive.StringSerializer;
import gaml.yaml.AliasNode;
import gaml.yaml.MappingNode;
import gaml.yaml.ScalarNode;
import gaml.yaml.YamlNode;
import gaml.yaml.ahchor.YamlAnchor;
import gaml.yaml.ahchor.YamlAnchorCodeStore;
import gaml.yaml.ahchor.YamlAnchorObjectStore;

import org.junit.Test;

public class ComplexSerializerTest {
	
	class SubFoo {
		String subname;
		Foo foo;

		public SubFoo (String subname, Foo foo) { this.subname = subname; this.foo = foo; }
		public Foo getFoo () { return foo; }
	}

	class Foo {
		String name;
		Integer id;

		SubFoo subfoo;

		public Foo (String name, int id, String subname) { this.name = name; this.id = id; this.subfoo = new SubFoo (subname, this); }

		public String getName () { return name; }
		public int getId () { return id; }
		public SubFoo getSubFoo () { return subfoo; }
	}

	class Bar extends Foo {
		String barname;
	
		public Bar (String name, int id, String subname, String barname) {
			super (name, id, subname);
			this.barname = barname;
		}
		
		public String getBarName () { return barname; }
	}

	@Test
	public void testSerialize () throws GamlException, SecurityException, NoSuchFieldException {
		assertEquals (String.class, Foo.class.getDeclaredField ("name").getType ());

		ClassSerializerStore store = new ClassSerializerStore ();
		store.setComplexFactory (new ComplexSerializerFactory (store));

		store.register (new ObjectSerializer ());
		store.register (new StringSerializer ());
		store.register (new IntegerSerializer ());
		store.register (int.class, store.get (Integer.class));

		assertTrue (store.contains (Foo.class.getDeclaredField ("name").getType ()));

		YamlAnchorObjectStore anchors = new YamlAnchorObjectStore ();

		Bar bar = new Bar ("Name", 0, "SubName", "BarName");
		
		assertEquals (bar, bar.getSubFoo ().getFoo ());

		YamlNode node = NodeObjectBridge.create (bar, null, Bar.class, store).parseObject (anchors).getNode ();

		for (YamlNode key: node.getMappingChildren ().keySet ())
			if ("subfoo".equals (key.getValue ()))
				for (YamlNode subkey: node.getMappingChildren ().get (key).getMappingChildren ().keySet ())
					if ("foo".equals (subkey.getValue ()))
						assertEquals (node.getMappingChildren ().get (key).getMappingChildren ().get (subkey).getAnchor (), node.getAnchor ());
	}
	
	@Test
	public void testDeserialize () throws GamlException {

		MappingNode node = new MappingNode (null);
		node.setAnchor (new YamlAnchor ("fooooo", node));

		node.getMappingChildren ().put (new ScalarNode (node).setValue ("barname"), new ScalarNode (node).setValue ("Bar Name"));
		node.getMappingChildren ().put (new ScalarNode (node).setValue ("name"), new ScalarNode (node).setValue ("Name"));
		node.getMappingChildren ().put (new ScalarNode (node).setValue ("id"), new ScalarNode (node).setValue ("90"));

		YamlNode subfooKey = new ScalarNode (node).setValue ("subfoo");
		
		node.getMappingChildren ().put (subfooKey, new MappingNode (node));
		node.getMappingChildren ().get (subfooKey).getMappingChildren ().put (new ScalarNode (node).setValue ("subname"), new ScalarNode (node.getMappingChildren ().get ("subfoo")).setValue ("SubFoo Name"));
		node.getMappingChildren ().get (subfooKey).getMappingChildren ().put (new ScalarNode (node).setValue ("foo"), new AliasNode (node.getMappingChildren ().get ("subfoo"), node.getAnchor ()));

		ClassSerializerStore store = new ClassSerializerStore ();
		store.setComplexFactory (new ComplexSerializerFactory (store));

		store.register (new ObjectSerializer ());
		store.register (new StringSerializer ());
		store.register (new IntegerSerializer ());
		store.register (int.class, store.get (Integer.class));

		Bar bar = NodeObjectBridge.create (node, Bar.class, store).parseNode (new YamlAnchorCodeStore ()).getObject ();

		assertEquals ("Bar Name", bar.getBarName ());
		assertEquals (90, bar.getId ());

		assertEquals (bar.getSubFoo ().getFoo (), bar.getSubFoo ().getFoo ().getSubFoo ().getFoo ());
	}
}